/*-----------------------------------*
 | Copyright (c) Agoston Roth, 2010. |
 *-----------------------------------*/

/*-------------*
 | Description |
 *-------------*-----------------------------------------------------------------------------*
 | Class GeneriCurve can also be used as a base class for any type of curve.                 |
 | This class provides methods only for rendering and updating (i.e. does not implement      |
 | coordinate or blending functions). When using inheritance, the coordinates of the         |
 | curve points, first and second order derivatives must be set either by one of the         |
 | methods (e.g. constructor) of the derived class, or via the inherited methods             |
 |                                                                                           |
 | GLboolean SetDerivative(GLuint order, GLuint index, double x, double y, double z = 0.0);  |
 | GLboolean SetDerivative(GLuint order, GLuint index, const DCoordinate &v);                |
 |                                                                                           |
 | The rendering is based on vertex buffer objects. Notice that, for efficiency reasons      |
 | all double coordinates are truncated to float numbers when creating/loading the data      |
 | of vertex buffer objects.                                                                 |
 *-------------------------------------------------------------------------------------------*/

#pragma once

#include <GL/glew.h>
#include "DCoordinates.h"
#include "Matrices.h"

namespace cagd
{
    class GenericCurve
    {
        friend class ApproximatingSpline;

    protected:
        GLenum              _usage_flag;
        RowMatrix<GLuint>   _vbo_derivative;
        Matrix<DCoordinate> _derivative;

    public:

        // default and special constructor
        GenericCurve(GLuint point_count = 0, GLuint maximum_order_of_derivative = 2, GLenum usage_flag = GL_STATIC_DRAW);

        // copy constructor
        GenericCurve(const GenericCurve &curve);

        // assignment operator
        GenericCurve& operator =(const GenericCurve &rhs);

        // vertex buffer object handling methods
        GLvoid DeleteVertexBufferObjects();

        GLboolean RenderDerivative(GLuint order, GLenum render_mode) const;

        GLboolean RenderCurvePoints(GLenum render_mode = GL_LINE_STRIP) const;
        GLboolean RenderTangentVectors(GLenum render_mode = GL_LINES) const;
        GLboolean RenderAccelerationVectors(GLenum render_mode = GL_LINES) const;
        GLboolean UpdateVertexBufferObjects(GLenum usage_flag = GL_STATIC_DRAW);

        // update and query methods
        GLboolean SetDerivative(GLuint order, GLuint index, GLdouble x, GLdouble y, GLdouble z = 0.0);
        GLboolean SetDerivative(GLuint order, GLuint index, const DCoordinate &v);
        GLboolean GetDerivative(GLuint order, GLuint index, DCoordinate &result) const;
        GLint GetMaximumOrderOfDerivatives() const;

        // destructor
        virtual ~GenericCurve();
    };
}
